Script description: This script manipulates the raw
data of the retrieved datasets to show summary tables and figures.
Script structure:
- Number of datasets and relevance categories.2. Queries performance -
3. Temporal duration - 4. Spatial range - 5. Temporal duration, spatial
range, and relevance - 6. EBV data types - 7. Data format - 8. Datasets
accessibility and relevance per year
(TODO)
Journals
Taxonomic coverage
Dataset location
Temporal and spatial information location
library(dplyr)
library(reshape)
library(ggplot2)
library(hrbrthemes)
library(ggpubr)
library(tidyr)
library(stringr)
library(ggrepel)
library(readxl)
source("Functions.R")
Some parameters for the plots:
my.theme<-theme(axis.text=element_text(size=15),
axis.title = element_text(size = 17),
legend.text=element_text(size=10),
legend.title = element_text(size=12),
plot.title = element_text(face="bold",size=14,margin=margin(0,0,20,0),hjust = 0.5),
axis.title.y = element_text(margin = margin(t = 0, r = 10, b = 0, l = 0)),
axis.title.x = element_text(margin = margin(t = 15, r = 0, b = 0, l = 0)),
panel.background = element_rect(fill = 'white'))
Read data
#dataset <- read.csv("repo_datasets.csv", header = TRUE,sep=";")
dataset <- read_excel("df_repository.xlsx")
table(dataset$valid_yn)
no yes
53 108
table(dataset$reason_non_valid[which(dataset$valid_yn=="no")])
location non-field experiment non-relevant information non biological not in the field
37 4 2 1 3
other
6
Eliminate empty rows and those where dataset_relevance is left in
blank (they correspond to referred publications in the retrieved
datasets and are not used in these analyses):
dataset <- dataset[dataset$dataset_relevance != "",]
dataset <- dataset %>% dplyr::filter(valid_yn == "yes")
dataset$dataset_relevance <- as.factor(dataset$dataset_relevance)
dataset <- dataset[dataset$source != "semantic_scholar",]
dataset$id_query <- stringr::str_trim(dataset$id_query )
dataset$dataset_relevance <- str_trim(dataset$dataset_relevance )
head(dataset)
1. Number of datasets and relevance categories
df_N_relevance <- count_by_relevance(dataset)
df_N_relevance
1.1 Relevance counts by source
df_rel_source <- count_relevance_by_source(df = dataset)
df_rel_source
NA
NA
Plot the results:
df_rel_source_melt <- melt(df_rel_source, id ="relevance")
Error in data.frame(ids, x, data[, x]) :
les arguments impliquent des nombres de lignes différents : 0, 1
3. Temporal duration
3.1 Temporal duration counts
How many publications without temporal duration data?
nNa <- count_not.reported_temporal.duration(dataset)
print(paste(nNa, "publications without temporal duration data"))
Publication counts by temporal duration (years):
df_duration_counts <- count_durations(df = dataset, order_by = "counts")
df_duration_counts
Plot the results:
plot_temp_duration <- plot_duration_counts(df = df_duration_counts,
counts_Na = nNa)
plot_temp_duration
#ggsave("plots_repo/plot_temp_duration.png", height = 7, width = 12)
Average duration (for those with data):
dataset_temp_duration <- subset(dataset,
temporal_duration_y > 0 | temporal_duration_y == "no",
select = c(temporal_duration_y,id_query))
dataset_temp_duration$temporal_duration_y <- as.numeric(dataset_temp_duration$temporal_duration_y)
print(paste("mean of",
round(mean(na.omit(dataset_temp_duration$temporal_duration_y)),digits = 1),
"years"))
3.1 Temporal duration counts per relevance category
plot_duration_relevance.categories <- plot_duration_relevance(df = dataset,
counts_Na = nNa)
plot_duration_relevance.categories
ggsave("plots_repo/plot_duration_relevance.categories.png", height = 7, width = 9)
4. Spatial range
4.1 count spatial range publications
WARNING: publications that cant be accessed are not counted
How many publications without spatial range data?
n_not_reported <- count_not.reported_spatial_range(dataset)
print(paste(n_not_reported, "publications without spatial range data"))
Spatial ranges are divided according to the thresholds established to
determine a low, moredate and high spatial range: <5000, 500-15000,
>15000
plot_spatial_range_counts <- plot_spat.range_counts(dataset)
plot_spatial_range_counts
#ggsave("plots_repo/plot_spatial_range_counts.png", height = 7, width = 7)
Average spatial range (for those with data):
dataset1 <- dataset[dataset$dataset_relevance != "cant access",]
dataset1$dataset_relevance <- as.factor(dataset1$dataset_relevance)
spatial_range_km2_vec <- dataset1$spatial_range_km2[dataset1$spatial_range_km2 != ""]
spatial_range_km2_vec <- spatial_range_km2_vec[!is.na(spatial_range_km2_vec)]
spatial_range_km2_vec <- as.numeric(spatial_range_km2_vec)
print(paste("mean of",
round(mean(na.omit(spatial_range_km2_vec)), digits = 0),
"km2"))
5. Temporal duration, spatial range, relevance
plot_spatial_temporal_relevance <- plot_spat_temp_relevance(df = dataset)
plot_spatial_temporal_relevance
#ggsave("plots_repo/plot_spatial_temporal_relevance.png", height = 7, width = 9)
6. EBV data types
df_data_type_counts <- compute_df_data.type(df = dataset)
df_data_type_counts
Plot the results
plot_data_type <- plot_data.type_counts(df_data_type_counts)
plot_data_type
#ggsave("plots_repo/plot_data_type.png", height = 7, width = 9)
8. Datasets accessibility and relevance per year
Raw plot relevance per year
plot_relevance_access_year <- plot_relevance_year(dataset)
plot_relevance_access_year
#ggsave("plots_repo/plot_relevance_access_year.png", height = 7, width = 14)
Relevance per year (intervals):
df_relevance_year.range <- compute_df_relevance_year.range(dataset)
df_relevance_year.range
Plot the results:
plot_relevance_year.range <- plot_relevance_year.range_repo(dataset)
plot_relevance_year.range
#ggsave("plots_repo/plot_relevance_year.range.png", height = 7, width = 9)
9. Journals
Count publications per journal
dataset.j <- dataset[dataset$Journal != "" & dataset$Journal != "no",]
df_journals_counts <- as.data.frame(table(dataset.j$Journal))
colnames(df_journals_counts) = c("Journal", "Publication_counts")
df_journals_counts <- df_journals_counts[order(-df_journals_counts$Publication_counts),]
df_journals_counts
print(paste("A total of", length(df_journals_counts$Journal), "journals" ))
location - dataset type
We evaluate the feasibility to automatically retrieve the information
on the dataset type by looking at whether authors make explicit the type
of dataset in either the title or abstract.
Type of dataset should fall in one of the following categories or
synonyms:
df_dataset_types <- read.csv("../data/dataset_types.csv", sep = ";")
df_dataset_types
I will add the following synonyms:
presence-absence: detection, capture
EBV genetic analyses: 16S, 18S, genetic data, microsatelites,
barcodes(?), haplotypes, eDNA, SNPs
df_dataset_types[nrow(df_dataset_types)+1,] <- c("presence-absence", "detection", "synonym")
df_dataset_types[nrow(df_dataset_types)+1,] <- c("presence-absence", "capture", "synonym")
df_dataset_types[nrow(df_dataset_types)+1,] <- c("EBV genetic analyses", "16S", "methods")
df_dataset_types[nrow(df_dataset_types)+1,] <- c("EBV genetic analyses", "18S", "methods")
df_dataset_types[nrow(df_dataset_types)+1,] <- c("EBV genetic analyses", "barcodes", "methods")
df_dataset_types[nrow(df_dataset_types)+1,] <- c("EBV genetic analyses", "haplotypes", "methods")
df_dataset_types[nrow(df_dataset_types)+1,] <- c("EBV genetic analyses", "eDNA", "methods")
df_dataset_types[nrow(df_dataset_types)+1,] <- c("EBV genetic analyses", "SNPs", "methods")
df_dataset_types
Detecting the words in title or abstract
dataset1 <- dataset[-which(is.na(dataset[,"description"])),]
dataset2 <- dataset1[-which(dataset1$title == ""),]
url <- c()
dataset_type <- c()
keyword_abs <- list()
keyword_title <- list()
#keyword_type <- c()
in_title <- c()
in_abstract <- c()
for (i in 1:nrow(dataset2)) {
dataset_type[i] <- dataset2[i, "data_type"]
url[i] <- dataset2[i, "url"]
# search on the abstract and note the list of keywords that match the dataset types
keyword_abs[[i]] <- unique(get_keywords(input_string = dataset2$description[i],
dataset_types = df_dataset_types))
# if the list of keywords has 1 or more entry, then note that we found information in the abstract
if(length(keyword_abs[i][!sapply(keyword_abs[i], is.null)]) == 0){
in_abstract[i] <- "no"
} else if (length(keyword_abs[i][!sapply(keyword_abs[i], is.null)]) > 0){
in_abstract[i] <- "yes"
}
# search on the title and note the list of keywords that match the dataset types
keyword_title[[i]] <- unique(get_keywords(input_string = dataset2$title[i],
dataset_types = df_dataset_types))
# if the list of keywords has 1 or more entry, then note that we found information in the abstract
if(length(keyword_title[i][!sapply(keyword_title[i], is.null)]) == 0){
in_title[i] <- "no"
} else if (length(keyword_title[i][!sapply(keyword_title[i], is.null)]) > 0){
in_title[i] <- "yes"
}
}
#data.frame(dataset_type, keyword_abs, keyword_title, in_title, in_abstract)
df_data_type_abs <- data.frame(url, dataset_type, in_abstract, in_title)
df_data_type_abs$keyword_abs <- keyword_abs
#eliminate those datasets without data_type info
df_data_type_abs1 <- df_data_type_abs[df_data_type_abs$dataset_type != "",]
df_data_type_abs1
For some reason, keyword_title has 3 less entries that
keyword_abstract, and I can’t figure out why. So for now I cant obtain
the list of words that appear in the title.
print(paste(length(which(df_data_type_abs1$in_abstract == "yes")),
"with dataset type or synonym explicit in the abstract, out of", length(df_data_type_abs1$in_abstract)))
print(paste("so",
round(length(which(df_data_type_abs1$in_abstract == "yes"))/length(df_data_type_abs1$in_abstract)*100, 1),
"%"))
print(paste(length(which(df_data_type_abs1$in_title == "yes")),
"with dataset type or synonym explicit in the title, out of", length(df_data_type_abs1$in_title)))
print(paste("so",
round(length(which(df_data_type_abs1$in_title == "yes"))/length(df_data_type_abs1$in_title)*100, 1),
"%"))
LS0tDQp0aXRsZTogIk92ZXJ2aWV3IG9mIHJldHJpZXZlZCBkYXRhc2V0cyINCm91dHB1dDoNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCi0tLQ0KDQoqKlNjcmlwdCBkZXNjcmlwdGlvbjoqKiBUaGlzIHNjcmlwdCBtYW5pcHVsYXRlcyB0aGUgcmF3IGRhdGEgb2YgdGhlIHJldHJpZXZlZCBkYXRhc2V0cyB0byBzaG93IHN1bW1hcnkgdGFibGVzIGFuZCBmaWd1cmVzLg0KDQoqKlNjcmlwdCBzdHJ1Y3R1cmU6KioNCg0KMS4gIE51bWJlciBvZiBkYXRhc2V0cyBhbmQgcmVsZXZhbmNlIGNhdGVnb3JpZXMuMi4gUXVlcmllcyBwZXJmb3JtYW5jZSAtIDMuIFRlbXBvcmFsIGR1cmF0aW9uIC0gNC4gU3BhdGlhbCByYW5nZSAtIDUuIFRlbXBvcmFsIGR1cmF0aW9uLCBzcGF0aWFsIHJhbmdlLCBhbmQgcmVsZXZhbmNlIC0gNi4gRUJWIGRhdGEgdHlwZXMgLSA3LiBEYXRhIGZvcm1hdCAtIDguIERhdGFzZXRzIGFjY2Vzc2liaWxpdHkgYW5kIHJlbGV2YW5jZSBwZXIgeWVhcg0KDQooVE9ETykNCg0KOS4gIEpvdXJuYWxzDQoNCjEwLiBUYXhvbm9taWMgY292ZXJhZ2UNCg0KMTEuIERhdGFzZXQgbG9jYXRpb24NCg0KMTIuIFRlbXBvcmFsIGFuZCBzcGF0aWFsIGluZm9ybWF0aW9uIGxvY2F0aW9uDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVzaGFwZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoaHJicnRoZW1lcykNCmxpYnJhcnkoZ2dwdWJyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkoZ2dyZXBlbCkNCmxpYnJhcnkocmVhZHhsKQ0KDQpzb3VyY2UoIkZ1bmN0aW9ucy5SIikNCmBgYA0KDQpTb21lIHBhcmFtZXRlcnMgZm9yIHRoZSBwbG90czoNCg0KYGBge3J9DQpteS50aGVtZTwtdGhlbWUoYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTE1KSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTcpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMCksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIixzaXplPTE0LG1hcmdpbj1tYXJnaW4oMCwwLDIwLDApLGhqdXN0ID0gMC41KSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMCwgciA9IDEwLCBiID0gMCwgbCA9IDApKSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTUsIHIgPSAwLCBiID0gMCwgbCA9IDApKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gJ3doaXRlJykpDQoNCmBgYA0KDQoNCg0KDQoNCiMjIyMgUmVhZCBkYXRhDQoNCg0KYGBge3J9DQoNCiNkYXRhc2V0IDwtIHJlYWQuY3N2KCJyZXBvX2RhdGFzZXRzLmNzdiIsIGhlYWRlciA9IFRSVUUsc2VwPSI7IikNCmRhdGFzZXQgPC0gcmVhZF9leGNlbCgiZGZfcmVwb3NpdG9yeS54bHN4IikNCnRhYmxlKGRhdGFzZXQkdmFsaWRfeW4pDQpgYGANCmBgYHtyfQ0KDQp0YWJsZShkYXRhc2V0JHJlYXNvbl9ub25fdmFsaWRbd2hpY2goZGF0YXNldCR2YWxpZF95bj09Im5vIildKQ0KYGBgDQoNCkVsaW1pbmF0ZSBlbXB0eSByb3dzIGFuZCB0aG9zZSB3aGVyZSBkYXRhc2V0X3JlbGV2YW5jZSBpcyBsZWZ0IGluIGJsYW5rICh0aGV5IGNvcnJlc3BvbmQgdG8gcmVmZXJyZWQgcHVibGljYXRpb25zIGluIHRoZSByZXRyaWV2ZWQgZGF0YXNldHMgYW5kIGFyZSBub3QgdXNlZCBpbiB0aGVzZSBhbmFseXNlcyk6DQpgYGB7cn0NCmRhdGFzZXQgPC0gZGF0YXNldFtkYXRhc2V0JGRhdGFzZXRfcmVsZXZhbmNlICE9ICIiLF0NCmRhdGFzZXQgPC0gZGF0YXNldCAlPiUgZHBseXI6OmZpbHRlcih2YWxpZF95biA9PSAieWVzIikNCmRhdGFzZXQkZGF0YXNldF9yZWxldmFuY2UgPC0gYXMuZmFjdG9yKGRhdGFzZXQkZGF0YXNldF9yZWxldmFuY2UpDQoNCmRhdGFzZXQgPC0gZGF0YXNldFtkYXRhc2V0JHNvdXJjZSAhPSAic2VtYW50aWNfc2Nob2xhciIsXQ0KZGF0YXNldCRpZF9xdWVyeSAgPC0gc3RyaW5ncjo6c3RyX3RyaW0oZGF0YXNldCRpZF9xdWVyeSApDQpkYXRhc2V0JGRhdGFzZXRfcmVsZXZhbmNlICA8LSBzdHJfdHJpbShkYXRhc2V0JGRhdGFzZXRfcmVsZXZhbmNlICkNCmhlYWQoZGF0YXNldCkNCmBgYA0KDQoNCg0KIyMgMS4gTnVtYmVyIG9mIGRhdGFzZXRzIGFuZCByZWxldmFuY2UgY2F0ZWdvcmllcw0KDQoNCmBgYHtyfQ0KDQoNCmRmX05fcmVsZXZhbmNlIDwtIGNvdW50X2J5X3JlbGV2YW5jZShkYXRhc2V0KQ0KDQpkZl9OX3JlbGV2YW5jZQ0KYGBgDQoNCg0KDQojIyMgMS4xIFJlbGV2YW5jZSBjb3VudHMgYnkgc291cmNlDQoNCmBgYHtyfQ0KDQpkZl9yZWxfc291cmNlIDwtIGNvdW50X3JlbGV2YW5jZV9ieV9zb3VyY2UoZGYgPSBkYXRhc2V0KQ0KDQpkZl9yZWxfc291cmNlDQoNCg0KYGBgDQoNClBsb3QgdGhlIHJlc3VsdHM6DQoNCmBgYHtyfQ0KDQpkZl9yZWxfc291cmNlX21lbHQgPC0gbWVsdChkZl9yZWxfc291cmNlLCBpZCA9InJlbGV2YW5jZSIpDQoNCnBsb3RfcmVsZXZhbmNlX3NvdXJjZSA8LSBnZ3Bsb3QoZGZfcmVsX3NvdXJjZV9tZWx0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyh4PXJlbGV2YW5jZSwgeT12YWx1ZSwgZ3JvdXAgPSB2YXJpYWJsZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB2YXJpYWJsZSxzaGFwZT12YXJpYWJsZSApKSArDQogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gcmV2KGxldmVscyhkZl9yZWxfc291cmNlX21lbHQkcmVsZXZhbmNlKSkpKw0KICAgIGdlb21fc2VnbWVudCggYWVzKHg9cmVsZXZhbmNlICx4ZW5kPXJlbGV2YW5jZSwgeT0wLCB5ZW5kPW1heCh2YWx1ZSkpLCBjb2xvcj0iZ3JleSIpICsNCiAgICBnZW9tX3BvaW50KHNpemU9NywgYWxwaGEgPSAwLjgpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgICMgdGhlbWVfaXBzdW0oKSArDQogICAgdGhlbWUoDQogICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICBsZWdlbmQucG9zaXRpb249InRvcCINCiAgICApICsNCiAgICB4bGFiKCJRdWVyeSBJRCIpKw0KICAgIHlsYWIoInB1YmxpY2F0aW9ucyBjb3VudHMiKSArDQogICAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJncmF5NjAiLCAicmVkIiwicHVycGxlMiIsICJkb2RnZXJibHVlIiwgImJsYWNrIiwgImJsYWNrIikpKw0KICAgIyBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxNSwgMTksIDE5LCAxOSwgMSwxMykpKw0KICAgIG15LnRoZW1lDQoNCg0KcGxvdF9yZWxldmFuY2Vfc291cmNlDQoNCiNnZ3NhdmUoInBsb3RzX3JlcG8vcGxvdF9yZWxldmFuY2Vfc291cmNlLnBuZyIsIGhlaWdodCA9IDcsIHdpZHRoID0gMTIpDQoNCmBgYA0KDQoNCg0KIyMgMi4gUXVlcmllcyBwZXJmb3JtYW5jZQ0KDQojIyMgMi4xLiBOIHB1YmxpY2F0aW9ucyBhbmQgcmVsZXZhbmNlIGNhdGVnb3JpZXMgcGVyIHF1ZXJ5DQoNCiMjIyMgR3JvdXBlZCBxdWVyaWVzDQoNCmBgYHtyfQ0KDQpkYXRhc2V0JGlkX3F1ZXJ5IDwtIGFzLmZhY3RvcihkYXRhc2V0JGlkX3F1ZXJ5KQ0KZGZfcXVlcmllc19jb3VudHMgPC0gY29tcHV0ZV9kZl9uX3JlbGV2YW5jZV9xdWVyaWVzKGRhdGEgPSBkYXRhc2V0KQ0KDQpkZl9xdWVyaWVzX2NvdW50cw0KYGBgDQoNClBsb3QgdGhlIHJlc3VsdHM6DQpgYGB7cn0NCmRmX3F1ZXJpZXNfY291bnRzX2FsbCA8LSBkYXRhc2V0ICU+JSANCiAgZ3JvdXBfYnkoZGF0YXNldF9yZWxldmFuY2UsIGlkX3F1ZXJ5KSAlPiUgDQogIHN1bW1hcmlzZShuID0gbigpKSANCg0KZGZfcXVlcmllc19jb3VudHNfYWxsIDwtIGRmX3F1ZXJpZXNfY291bnRzX2FsbCAlPiUgZHBseXI6OmZpbHRlcihkYXRhc2V0X3JlbGV2YW5jZSAlaW4lIGMoIlgiLCAiTCIsICJNIiwgIkgiKSkgJT4lIG11dGF0ZShkYXRhc2V0X3JlbGV2YW5jZSA9IGZhY3RvcihkYXRhc2V0X3JlbGV2YW5jZSkpDQoNCnBsb3RfZ3JvdXAucXVlcmllc19yZWxldmFuY2UgIDwtIGdncGxvdChkZl9xdWVyaWVzX2NvdW50c19hbGwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHg9aWRfcXVlcnksIHk9biwgZ3JvdXAgPSBkYXRhc2V0X3JlbGV2YW5jZSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBkYXRhc2V0X3JlbGV2YW5jZSxzaGFwZT1kYXRhc2V0X3JlbGV2YW5jZSApKSArDQogIGdlb21fc2VnbWVudCggYWVzKHg9aWRfcXVlcnkgLHhlbmQ9aWRfcXVlcnksIHk9MCwgeWVuZD1tYXgobikpLCBjb2xvcj0iZ3JleSIpICsNCiAgICBnZW9tX3BvaW50KHNpemU9NCwgYWxwaGEgPSAwLjgpICsNCiAgICBjb29yZF9mbGlwKCkgKw0KICAgICMgdGhlbWVfaXBzdW0oKSArDQogICAgdGhlbWUoDQogICAgICBwYW5lbC5ncmlkLm1pbm9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICBsZWdlbmQucG9zaXRpb249InRvcCINCiAgICApICsNCiAgICB4bGFiKCJRdWVyeSBJRCIpKw0KICAgIHlsYWIoInB1YmxpY2F0aW9ucyBjb3VudHMiKSArDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoICJyZWQiLCJwdXJwbGUyIiwgImRvZGdlcmJsdWUiLCAiYmxhY2siKSkrDQogICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMTksIDE5LCAxOSwgMSkpKw0KICAgIG15LnRoZW1lDQoNCnBsb3RfZ3JvdXAucXVlcmllc19yZWxldmFuY2UgDQojZ2dzYXZlKCJwbG90c19yZXBvL3Bsb3RfZ3JvdXAucXVlcmllc19yZWxldmFuY2VfYWxsLnBuZyIsIGhlaWdodCA9IDcsIHdpZHRoID0gMTIpDQpgYGANCg0KLSAgIFF1ZXJ5IDQgZGVsaXZlcnMgdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHJlbGV2YW50IGRhdGFzZXRzIChoaWdoZXN0IG51bWJlciBvZiBIaWdoLCBNb2RlcmF0ZSBhbmQgTG93IHJlbGV2YW5jZSBkYXRhc2V0cyksIGJ1dCBhbHNvIHJldHJpZXZlcyBieSBmYXIgdGhlIGhpZ2hlciBhbW91bnQgb2YgcHVibGljYXRpb24uDQoNCi0gICBTb21lIHF1ZXJpZXMgZG8gbm90IGFkZCBhbnkgcmVsZXZhbnQgcHVibGljYXRpb24gKGUuZy4gIjAsNiw1LDciIG9yICI3LDIsOSIpLg0KDQoNCiMjIyMgSW5kaXZpZHVhbCBxdWVyaWVzDQoNCmBgYHtyfQ0KDQpjb252ZXJ0X3F1ZXJ5ID0gZGF0YS5mcmFtZSgiaWRfcXVlcnkiID0gYXMuY2hhcmFjdGVyKHNlcSgwLDEwKSksICJxdWVyeSIgPSBjKA0KInN1cnZleSArIHNwZWNpZXMiLA0KInRpbWUgc2VyaWVzICsgc3BlY2llcyIsDQoiaW52ZW50b3J5ICsgc3BlY2llcyIsDQoic3BlY2llcyIsDQoiYWJ1bmRhbmNlICsgc3BlY2llcyIsDQoib2NjdXJyZW5jZSArIHNwZWNpZXMiLA0KInBvcHVsYXRpb24gKyBzcGVjaWVzIiwNCiJzaXRlcyArIHNwZWNpZXMiLA0KInNhbXBsaW5nICsgc3BlY2llcyIsDQoiY29sbGVjdGlvbiArIHNwZWNpZXMiLA0KImRlbnNpdHkgKyBzcGVjaWVzIg0KICANCikpDQoNCg0KZGF0YXNldF9xDQpgYGANCg0KYGBge3J9DQoNCiNzcGxpdCByb3dzIGluIGZ1bmN0aW9uIG9mIGNoYXJhY3RlciBjb21hcw0KDQpkYXRhc2V0X3EgPC0gZGF0YXNldCAlPiUgICAgICAgICAgICAgICANCiAgc2VwYXJhdGVfcm93cyhpZF9xdWVyeSwgc2VwPSIsIikgDQpkYXRhc2V0X3EgPC0gbWVyZ2UoZGF0YXNldF9xLCBjb252ZXJ0X3F1ZXJ5LCBieS5hbGw9ImlkX3F1ZXJ5IikNCg0KZGF0YXNldF9xJHF1ZXJ5ICA8LSBmYWN0b3IoZGF0YXNldF9xJHF1ZXJ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPSBjKCJzcGVjaWVzIiwgIm9jY3VycmVuY2UgKyBzcGVjaWVzIiwgImludmVudG9yeSArIHNwZWNpZXMiLCAiY29sbGVjdGlvbiArIHNwZWNpZXMiLCAic2FtcGxpbmcgKyBzcGVjaWVzIiwgInN1cnZleSArIHNwZWNpZXMiICwgInBvcHVsYXRpb24gKyBzcGVjaWVzIiwgInNpdGVzICsgc3BlY2llcyIsICJkZW5zaXR5ICsgc3BlY2llcyIsICJhYnVuZGFuY2UgKyBzcGVjaWVzIiAsICJ0aW1lIHNlcmllcyArIHNwZWNpZXMiICkpDQpkYXRhc2V0X3ENCg0KYGBgDQpgYGB7cn0NCmRmX3F1ZXJpZXNfY291bnRzX2luZCA8LSBkYXRhc2V0X3EgJT4lIA0KICBncm91cF9ieShkYXRhc2V0X3JlbGV2YW5jZSwgcXVlcnkpICU+JSANCiAgc3VtbWFyaXNlKG4gPSBuKCkpIA0KDQpkZl9xdWVyaWVzX2NvdW50c19pbmQgPC0gZGZfcXVlcmllc19jb3VudHNfaW5kICU+JSBkcGx5cjo6ZmlsdGVyKGRhdGFzZXRfcmVsZXZhbmNlICVpbiUgYygiWCIsICJMIiwgIk0iLCAiSCIpKSAlPiUgbXV0YXRlKGRhdGFzZXRfcmVsZXZhbmNlID0gZmFjdG9yKGRhdGFzZXRfcmVsZXZhbmNlKSkNCg0KcGxvdF9xdWVyaWVzX3JlbGV2YW5jZV9jb3VudHMgPC0gZ2dwbG90KGRmX3F1ZXJpZXNfY291bnRzX2luZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoeD1xdWVyeSwgeT1uLCBncm91cCA9IGRhdGFzZXRfcmVsZXZhbmNlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGRhdGFzZXRfcmVsZXZhbmNlLHNoYXBlPWRhdGFzZXRfcmVsZXZhbmNlICkpICsNCiAgZ2VvbV9zZWdtZW50KCBhZXMoeD1xdWVyeSAseGVuZD1xdWVyeSwgeT0wLCB5ZW5kPW1heChuKSksIGNvbG9yPSJncmV5IikgKw0KICAgIGdlb21fcG9pbnQoc2l6ZT00LCBhbHBoYSA9IDAuOCkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgIyB0aGVtZV9pcHN1bSgpICsNCiAgICB0aGVtZSgNCiAgICAgIHBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbj0idG9wIg0KICAgICkgKw0KICAgIHhsYWIoIlF1ZXJ5IElEIikrDQogICAgeWxhYigicHVibGljYXRpb25zIGNvdW50cyIpICsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYyggInJlZCIsInB1cnBsZTIiLCAiZG9kZ2VyYmx1ZSIsICJibGFjayIpKSsNCiAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxOSwgMTksIDE5LCAxKSkrDQogICAgbXkudGhlbWUNCg0KcGxvdF9xdWVyaWVzX3JlbGV2YW5jZV9jb3VudHMNCg0KDQpgYGANCg0KLSBxdWVyeSA0IHNob3dzIHRoZSBoaWdoZXN0IG51bWJlciBvZiByZWxldmFudCBkYXRhc2V0cyBmb3IgaGlnaCwgbW9kZXJhdGUgYW5kIGxvdyByZWxldmFuY2UgZGF0YXNldHMsIGJ1dCByZXRyaWV2ZXMgYWxtb3N0IGRvdWJsZSBudW1iZXIgb2YgYXJ0aWNsZXMgKH43MCkgY29tcGFyZWQgdG8gdGhlIHJlc3Qgb2YgcXVlcmllcy4NCg0KLSBxdWVyaWVzIDUgYW5kIDcgYXJlIGFibGUgdG8gcmV0cmlldmUgc29tZSByZWxldmFudCBkYXRhc2V0cyB3aXRoIH4yNSBwdWJsaWNhdGlvbnMgcmV0cmlldmVkLg0KDQoNCiMjIyAyLjIgQ2xhc3NpZnkgcXVlcmllcyBieSB0aGVpciByZWxldmFuY2UgKGluZGV4KQ0KDQpQdWN0dWF0aW9ucyBmb3IgdGhlIHJlbGV2YW5jZSBjYXRlZ29yaWVzOg0KDQotICAgSGlnaCA9IDUNCi0gICBNb2QgPSAyDQotICAgTG93ID0gMC41DQotICAgbm9uX3JlbGV2YW50ID0gMA0KDQoqSW5kZXggMSo6IGlzIHRoZSByZXN1bHQgb2Ygc3VtbWluZyB0aGUgcHVudHVhdGlvbnMgYXNzaWduZWQgdG8gZWFjaCByZWxldmFuY2UgY2F0ZWdvcnkNCg0KSW5kZXggMSA9IHN1bSBwdW5jdHVhdGlvbnMgPSAoTiBIaWdoIFwqIDUpICsgKE4gTW9kIFwqIDIpICsgKE4gTG93IFwqIDAuNSkNCg0KKkluZGV4IDIqOiBpcyB0aGUgSW5kZXgxIGJ1dCBhY2NvdW50aW5nIGZvciB0aGUgdG90YWwgbnVtYmVyIG9mIHB1YmxpY2F0aW9ucyByZXRyaWV2ZWQgYnkgdGhlIHF1ZXJ5Lg0KDQpJbmRleCAyID0gc3VtIHB1bmN0dWF0aW9ucyAvIG4gcHVibGljYXRpb25zIHJldHJpZXZlZA0KDQoNCiMjIyMgR3JvdXBlZCBxdWVyaWVzDQoNCmBgYHtyfQ0KDQpkZl9xdWVyaWVzX2NvdW50c19pbmRleCA8LSBjb21wdXRlX2luZGV4MTIoZGZfY291bnRzID0gZGZfcXVlcmllc19jb3VudHMsIG9yZGVyX2Jhc2VkX2luZGV4ID0gIjIiKSAjICIxIiBmb3Igb3JkZXJpbmcgYWNjb3JkaW5nIHRvIGluZGV4IDEsICIyIiBmb3IgaW5kZXggMg0KDQpkZl9xdWVyaWVzX2NvdW50c19pbmRleA0KDQpgYGANCg0KUXVlcmllcyAzLCA0LCAwLCBhbmQgNiBhcmUgdGhlIHRvcCA0IGluZGV4MSB2YWx1ZXMuIFF1ZXJpZXMgMyBhbmQgNCBoYXZlIGZhciBoaWdoZXIgaW5kZXggdGhhbiB0aGUgcmVzdC4NCg0KUGxvdCB0aGUgcmVzdWx0czoNCg0KYGBge3J9DQoNCnBsb3RfZ3JvdXAucXVlcmllc19pbmRleDEyIDwtIHBsb3RfcXVlcmllc19pbmRleChkZiA9IGRmX3F1ZXJpZXNfY291bnRzX2luZGV4KQ0KDQpwbG90X2dyb3VwLnF1ZXJpZXNfaW5kZXgxMg0KDQojZ2dzYXZlKCJwbG90c19yZXBvL3Bsb3RfZ3JvdXAucXVlcmllc19pbmRleDEyLnBuZyIsIGhlaWdodCA9IDUsIHdpZHRoID0gMTEpDQpgYGANCg0KLSAgIEluZGV4IDEgc2hvd3MgdGhhdCBxdWVyaWVzICIzIiBhbmQgIjQiIG9mZmVyIHRoZSBoaWdoZXIgcGVyZm9tYW5jZSwgZm9sbG93ZWQgYnkgIjYiIGFuZCAiNSIuDQoNCi0gICBJbmRleCAyIHNob3dzIHRoYXQgcXVlcmllICI2LDcsNSIgb2ZmZXIgdGhlIGhpZ2hlc3QgcGVyZm9ybWFuY2UsIGZvbGxvd2VkIGJ5ICI3LDgiLCAiNiw3IiwgYW5kICI1LDYsNyw4LDkiDQoNCg0KIyMjIyBpbmRpdmlkdWFsIHF1ZXJpZXMNCg0KYGBge3J9DQpkZl9xdWVyaWVzX2NvdW50c19pbmRleF9pbmQgPC0gY29tcHV0ZV9pbmRleDEyKGRmX2NvdW50cyA9IGRmX3F1ZXJpZXNfY291bnRzX2luZCwgb3JkZXJfYmFzZWRfaW5kZXggPSAiMiIpICMgIjEiIGZvciBvcmRlcmluZyBhY2NvcmRpbmcgdG8gaW5kZXggMSwgIjIiIGZvciBpbmRleCAyDQoNCmRmX3F1ZXJpZXNfY291bnRzX2luZGV4X2luZA0KYGBgDQoNCg0KUGxvdCB0aGUgcmVzdWx0cw0KDQpgYGB7cn0NCnBsb3RfcXVlcmllc19pbmRleDEyX2luZCA8LSBwbG90X3F1ZXJpZXNfaW5kZXgoZGYgPSBkZl9xdWVyaWVzX2NvdW50c19pbmRleF9pbmQpDQoNCnBsb3RfcXVlcmllc19pbmRleDEyX2luZA0KDQojZ2dzYXZlKCJwbG90c19yZXBvL3Bsb3RfaW5kLnF1ZXJpZXNfaW5kZXgxMi5wbmciLCBoZWlnaHQgPSA1LCB3aWR0aCA9IDExKQ0KYGBgDQoNCg0KDQojIyMgMi4zLiBGIFNDT1JFDQoNClByZWNpc2lvbg0KUmVjYWxsDQoNCkJpbmFyeSB2aWV3OiBNLEggcmVsZXZhbnQgfCBMLFggdW5yZXZlbGFudA0KDQoNCk4gcmVsZXZhbnQgZGF0YXNldHMgLT4gVHJ1ZSBQb3NpdGl2ZXMgKFRQKQ0KDQpOIHVucmVsZXZhbnQgZGF0YXNldHMgLT4gRmFsc2UgUG9zaXRpdmVzIChGUCkNCg0KU3VtIG9mIGFsbCByZWxldmFudCBwdWJsaWNhdGlvbnMgb2YgdGhlIGRhdGFzZXQgdGhhdCBhcmUgbm90IGRldGVjdGVkID0gRk4NCg0KUFJFQ0lTSU9OID0gVFAgLyBUUCArIEZQDQoNClJFQ0FMTCA9IFRQIC8gVFAgKyBGTg0KDQoNCkYgU0NPUkUgPSAyKiBwcmVjaXNpb24gKiByZWNhbGwgLyBwcmVjaXNpb24gKyByZWNhbGwNCg0KDQoNClNwbGl0IGdyb3VwZWQgcXVlcmllcyBpbnRvIGluZGl2aWR1YWwgb25lcw0KDQpgYGB7cn0NCg0KZGZfenNjb3Jlc19xdWVyaWVzIDwtIGNhbGN1bGF0ZV96LnNjb3JlX3F1ZXJpZXMoZGYgPSBkYXRhc2V0KQ0KDQpkZl96c2NvcmVzX3F1ZXJpZXMNCg0KYGBgDQoNClBsb3QgcmVzdWx0cw0KDQpgYGB7cn0NCnBsb3RfcXVlcmllc19zY29yZXMgPC0gZ2dwbG90KGRmX3pzY29yZXNfcXVlcmllcywgYWVzKHggPSBQcmVjaXNpb24sIHkgPSBSZWNhbGwsIGNvbG91ciA9IEZzY29yZSkpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMTApKw0KICBnZW9tX2xhYmVsX3JlcGVsKGFlcyhsYWJlbCA9IHF1ZXJpZXMpKSsNCiAgdGhlbWVfYncoKSsNCiAgbXkudGhlbWUNCg0KcGxvdF9xdWVyaWVzX3Njb3Jlcw0KDQojZ2dzYXZlKCJwbG90c19yZXBvL3Bsb3RfcXVlcmllc19zY29yZXMucG5nIiwgaGVpZ2h0ID0gNywgd2lkdGggPSA3KQ0KYGBgDQoNCg0KDQoNCiMjIDMuIFRlbXBvcmFsIGR1cmF0aW9uDQoNCiMjIyAzLjEgVGVtcG9yYWwgZHVyYXRpb24gY291bnRzDQoNCkhvdyBtYW55IHB1YmxpY2F0aW9ucyB3aXRob3V0IHRlbXBvcmFsIGR1cmF0aW9uIGRhdGE/DQoNCmBgYHtyfQ0Kbk5hIDwtIGNvdW50X25vdC5yZXBvcnRlZF90ZW1wb3JhbC5kdXJhdGlvbihkYXRhc2V0KQ0KDQpwcmludChwYXN0ZShuTmEsICJwdWJsaWNhdGlvbnMgd2l0aG91dCB0ZW1wb3JhbCBkdXJhdGlvbiBkYXRhIikpDQoNCmBgYA0KDQpQdWJsaWNhdGlvbiBjb3VudHMgYnkgdGVtcG9yYWwgZHVyYXRpb24gKHllYXJzKToNCg0KYGBge3J9DQogIA0KZGZfZHVyYXRpb25fY291bnRzIDwtIGNvdW50X2R1cmF0aW9ucyhkZiA9IGRhdGFzZXQsIG9yZGVyX2J5ID0gImNvdW50cyIpDQoNCmRmX2R1cmF0aW9uX2NvdW50cw0KYGBgDQoNClBsb3QgdGhlIHJlc3VsdHM6DQoNCmBgYHtyfQ0KcGxvdF90ZW1wX2R1cmF0aW9uIDwtIHBsb3RfZHVyYXRpb25fY291bnRzKGRmID0gZGZfZHVyYXRpb25fY291bnRzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHNfTmEgPSBuTmEpDQoNCnBsb3RfdGVtcF9kdXJhdGlvbg0KDQojZ2dzYXZlKCJwbG90c19yZXBvL3Bsb3RfdGVtcF9kdXJhdGlvbi5wbmciLCBoZWlnaHQgPSA3LCB3aWR0aCA9IDEyKQ0KDQpgYGANCg0KQXZlcmFnZSBkdXJhdGlvbiAoZm9yIHRob3NlIHdpdGggZGF0YSk6DQoNCmBgYHtyfQ0KDQpkYXRhc2V0X3RlbXBfZHVyYXRpb24gPC0gc3Vic2V0KGRhdGFzZXQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRlbXBvcmFsX2R1cmF0aW9uX3kgPiAwIHwgdGVtcG9yYWxfZHVyYXRpb25feSA9PSAibm8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCA9IGModGVtcG9yYWxfZHVyYXRpb25feSxpZF9xdWVyeSkpDQogIA0KICBkYXRhc2V0X3RlbXBfZHVyYXRpb24kdGVtcG9yYWxfZHVyYXRpb25feSA8LSBhcy5udW1lcmljKGRhdGFzZXRfdGVtcF9kdXJhdGlvbiR0ZW1wb3JhbF9kdXJhdGlvbl95KQ0KICANCiAgDQoNCnByaW50KHBhc3RlKCJtZWFuIG9mIiwNCiAgICAgICAgICAgIHJvdW5kKG1lYW4obmEub21pdChkYXRhc2V0X3RlbXBfZHVyYXRpb24kdGVtcG9yYWxfZHVyYXRpb25feSkpLGRpZ2l0cyA9IDEpLA0KICAgICAgICAgICAgInllYXJzIikpDQpgYGANCg0KIyMjIDMuMSBUZW1wb3JhbCBkdXJhdGlvbiBjb3VudHMgcGVyIHJlbGV2YW5jZSBjYXRlZ29yeQ0KDQpgYGB7cn0NCg0KDQpwbG90X2R1cmF0aW9uX3JlbGV2YW5jZS5jYXRlZ29yaWVzIDwtIHBsb3RfZHVyYXRpb25fcmVsZXZhbmNlKGRmID0gZGF0YXNldCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnRzX05hID0gbk5hKQ0KDQpwbG90X2R1cmF0aW9uX3JlbGV2YW5jZS5jYXRlZ29yaWVzDQoNCmdnc2F2ZSgicGxvdHNfcmVwby9wbG90X2R1cmF0aW9uX3JlbGV2YW5jZS5jYXRlZ29yaWVzLnBuZyIsIGhlaWdodCA9IDcsIHdpZHRoID0gOSkNCg0KYGBgDQoNCiMjIDQuIFNwYXRpYWwgcmFuZ2UNCg0KIyMjIDQuMSBjb3VudCBzcGF0aWFsIHJhbmdlIHB1YmxpY2F0aW9ucw0KDQpXQVJOSU5HOiBwdWJsaWNhdGlvbnMgdGhhdCBjYW50IGJlIGFjY2Vzc2VkIGFyZSBub3QgY291bnRlZA0KDQpIb3cgbWFueSBwdWJsaWNhdGlvbnMgd2l0aG91dCBzcGF0aWFsIHJhbmdlIGRhdGE/DQoNCmBgYHtyfQ0KDQpuX25vdF9yZXBvcnRlZCA8LSBjb3VudF9ub3QucmVwb3J0ZWRfc3BhdGlhbF9yYW5nZShkYXRhc2V0KQ0KDQpwcmludChwYXN0ZShuX25vdF9yZXBvcnRlZCwgInB1YmxpY2F0aW9ucyB3aXRob3V0IHNwYXRpYWwgcmFuZ2UgZGF0YSIpKQ0KDQpgYGANCg0KU3BhdGlhbCByYW5nZXMgYXJlIGRpdmlkZWQgYWNjb3JkaW5nIHRvIHRoZSB0aHJlc2hvbGRzIGVzdGFibGlzaGVkIHRvIGRldGVybWluZSBhIGxvdywgbW9yZWRhdGUgYW5kIGhpZ2ggc3BhdGlhbCByYW5nZTogXDw1MDAwLCA1MDAtMTUwMDAsIFw+MTUwMDANCg0KYGBge3J9DQoNCnBsb3Rfc3BhdGlhbF9yYW5nZV9jb3VudHMgPC0gcGxvdF9zcGF0LnJhbmdlX2NvdW50cyhkYXRhc2V0KQ0KDQpwbG90X3NwYXRpYWxfcmFuZ2VfY291bnRzDQoNCiNnZ3NhdmUoInBsb3RzX3JlcG8vcGxvdF9zcGF0aWFsX3JhbmdlX2NvdW50cy5wbmciLCBoZWlnaHQgPSA3LCB3aWR0aCA9IDcpDQoNCmBgYA0KDQpBdmVyYWdlIHNwYXRpYWwgcmFuZ2UgKGZvciB0aG9zZSB3aXRoIGRhdGEpOg0KDQpgYGB7cn0NCg0KZGF0YXNldDEgPC0gZGF0YXNldFtkYXRhc2V0JGRhdGFzZXRfcmVsZXZhbmNlICE9ICJjYW50IGFjY2VzcyIsXQ0KICANCiAgZGF0YXNldDEkZGF0YXNldF9yZWxldmFuY2UgPC0gYXMuZmFjdG9yKGRhdGFzZXQxJGRhdGFzZXRfcmVsZXZhbmNlKQ0KICANCiAgc3BhdGlhbF9yYW5nZV9rbTJfdmVjIDwtIGRhdGFzZXQxJHNwYXRpYWxfcmFuZ2Vfa20yW2RhdGFzZXQxJHNwYXRpYWxfcmFuZ2Vfa20yICE9ICIiXQ0KICANCiAgc3BhdGlhbF9yYW5nZV9rbTJfdmVjIDwtIHNwYXRpYWxfcmFuZ2Vfa20yX3ZlY1shaXMubmEoc3BhdGlhbF9yYW5nZV9rbTJfdmVjKV0NCiAgDQogIHNwYXRpYWxfcmFuZ2Vfa20yX3ZlYyA8LSBhcy5udW1lcmljKHNwYXRpYWxfcmFuZ2Vfa20yX3ZlYykgDQoNCg0KcHJpbnQocGFzdGUoIm1lYW4gb2YiLA0KICAgICAgICAgICAgcm91bmQobWVhbihuYS5vbWl0KHNwYXRpYWxfcmFuZ2Vfa20yX3ZlYykpLCBkaWdpdHMgPSAwKSwNCiAgICAgICAgICAgICJrbTIiKSkNCmBgYA0KDQojIyA1LiBUZW1wb3JhbCBkdXJhdGlvbiwgc3BhdGlhbCByYW5nZSwgcmVsZXZhbmNlDQoNCmBgYHtyfQ0KDQpwbG90X3NwYXRpYWxfdGVtcG9yYWxfcmVsZXZhbmNlIDwtIHBsb3Rfc3BhdF90ZW1wX3JlbGV2YW5jZShkZiA9IGRhdGFzZXQpDQoNCnBsb3Rfc3BhdGlhbF90ZW1wb3JhbF9yZWxldmFuY2UNCg0KI2dnc2F2ZSgicGxvdHNfcmVwby9wbG90X3NwYXRpYWxfdGVtcG9yYWxfcmVsZXZhbmNlLnBuZyIsIGhlaWdodCA9IDcsIHdpZHRoID0gOSkNCg0KYGBgDQoNCiMjIDYuIEVCViBkYXRhIHR5cGVzDQoNCmBgYHtyfQ0KDQpkZl9kYXRhX3R5cGVfY291bnRzIDwtIGNvbXB1dGVfZGZfZGF0YS50eXBlKGRmID0gZGF0YXNldCkNCg0KZGZfZGF0YV90eXBlX2NvdW50cw0KDQpgYGANCg0KUGxvdCB0aGUgcmVzdWx0cw0KDQpgYGB7cn0NCg0KcGxvdF9kYXRhX3R5cGUgPC0gcGxvdF9kYXRhLnR5cGVfY291bnRzKGRmX2RhdGFfdHlwZV9jb3VudHMpDQoNCnBsb3RfZGF0YV90eXBlDQoNCiNnZ3NhdmUoInBsb3RzX3JlcG8vcGxvdF9kYXRhX3R5cGUucG5nIiwgaGVpZ2h0ID0gNywgd2lkdGggPSA5KQ0KDQpgYGANCg0KIyMgNy4gRGF0YSBmb3JtYXQNCg0KDQpUaG9zZSBkYXRhc2V0cyBpbiB0aGUgcmVwb3NpdG9yeSB0aGF0IGFyZSByZWxldmFuY2UgY2F0ZWdvcnkgWCBkb24ndCBoYXZlIGZvcm1hdCBpbmZvcm1hdGlvbi4NCg0KYGBge3J9DQoNCnBsb3RfZGF0YV9mb3JtYXRfY291bnRzIDwtIHBsb3RfZGF0YS50eXBlX2Zvcm1hdChkYXRhc2V0KQ0KDQpwbG90X2RhdGFfZm9ybWF0X2NvdW50cw0KDQojZ2dzYXZlKCJwbG90c19yZXBvL3Bsb3RfZGF0YV9mb3JtYXRfY291bnRzLnBuZyIsIGhlaWdodCA9IDcsIHdpZHRoID0gOSkNCg0KYGBgDQoNCiMjIDguIERhdGFzZXRzIGFjY2Vzc2liaWxpdHkgYW5kIHJlbGV2YW5jZSBwZXIgeWVhcg0KDQpSYXcgcGxvdCByZWxldmFuY2UgcGVyIHllYXINCg0KYGBge3J9DQoNCnBsb3RfcmVsZXZhbmNlX2FjY2Vzc195ZWFyIDwtIHBsb3RfcmVsZXZhbmNlX3llYXIoZGF0YXNldCkNCg0KcGxvdF9yZWxldmFuY2VfYWNjZXNzX3llYXINCg0KI2dnc2F2ZSgicGxvdHNfcmVwby9wbG90X3JlbGV2YW5jZV9hY2Nlc3NfeWVhci5wbmciLCBoZWlnaHQgPSA3LCB3aWR0aCA9IDE0KQ0KDQpgYGANCg0KUmVsZXZhbmNlIHBlciB5ZWFyIChpbnRlcnZhbHMpOg0KDQpgYGB7cn0NCg0KZGZfcmVsZXZhbmNlX3llYXIucmFuZ2UgPC0gY29tcHV0ZV9kZl9yZWxldmFuY2VfeWVhci5yYW5nZShkYXRhc2V0KQ0KDQpkZl9yZWxldmFuY2VfeWVhci5yYW5nZQ0KDQpgYGANCg0KUGxvdCB0aGUgcmVzdWx0czoNCg0KYGBge3J9DQoNCnBsb3RfcmVsZXZhbmNlX3llYXIucmFuZ2UgPC0gcGxvdF9yZWxldmFuY2VfeWVhci5yYW5nZV9yZXBvKGRhdGFzZXQpDQoNCnBsb3RfcmVsZXZhbmNlX3llYXIucmFuZ2UNCg0KI2dnc2F2ZSgicGxvdHNfcmVwby9wbG90X3JlbGV2YW5jZV95ZWFyLnJhbmdlLnBuZyIsIGhlaWdodCA9IDcsIHdpZHRoID0gOSkNCg0KYGBgDQoNCg0KDQoNCiMjIDkuIEpvdXJuYWxzDQoNCg0KQ291bnQgcHVibGljYXRpb25zIHBlciBqb3VybmFsDQoNCmBgYHtyfQ0KDQpkYXRhc2V0LmogPC0gZGF0YXNldFtkYXRhc2V0JEpvdXJuYWwgIT0gIiIgJiBkYXRhc2V0JEpvdXJuYWwgIT0gIm5vIixdDQoNCmRmX2pvdXJuYWxzX2NvdW50cyA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRhdGFzZXQuaiRKb3VybmFsKSkNCg0KY29sbmFtZXMoZGZfam91cm5hbHNfY291bnRzKSA9IGMoIkpvdXJuYWwiLCAiUHVibGljYXRpb25fY291bnRzIikNCg0KZGZfam91cm5hbHNfY291bnRzIDwtIGRmX2pvdXJuYWxzX2NvdW50c1tvcmRlcigtZGZfam91cm5hbHNfY291bnRzJFB1YmxpY2F0aW9uX2NvdW50cyksXQ0KDQoNCmRmX2pvdXJuYWxzX2NvdW50cw0KDQoNCmBgYA0KDQoNCg0KDQoNCg0KDQpgYGB7cn0NCg0KcHJpbnQocGFzdGUoIkEgdG90YWwgb2YiLCBsZW5ndGgoZGZfam91cm5hbHNfY291bnRzJEpvdXJuYWwpLCAiam91cm5hbHMiICkpDQoNCmBgYA0KDQpgYGB7cn0NCg0KYGBgDQoNCg0KIyMgMTAuIFNvdXJjZSBvZiBpbmZvcm1hdGlvbiBhY3Jvc3MgdGltZQ0KDQoNCmBgYHtyfQ0KDQpkZi5zb3VyY2VfdGltZSA8LSBkZl9zb3VyY2VfdGltZShkZiA9IGRhdGFzZXQpDQoNCmRmLnNvdXJjZV90aW1lDQoNCmBgYA0KDQoNCg0KDQoNCmBgYHtyfQ0KZGZfcGxvdF9zb3VyY2VfdGltZSA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRmLnNvdXJjZV90aW1lJHllYXIsZGYuc291cmNlX3RpbWUkc291cmNlICkpDQoNCmNvbG5hbWVzKGRmX3Bsb3Rfc291cmNlX3RpbWUpIDwtIGMoInllYXIiLCAic291cmNlIiwgIk4iKQ0KDQpkZl9wbG90X3NvdXJjZV90aW1lJE4gPC0gYXMubnVtZXJpYyhkZl9wbG90X3NvdXJjZV90aW1lJE4pDQoNCg0KcGxvdF9zb3VyY2VfdGltZSA8LSBnZ3Bsb3QoZGZfcGxvdF9zb3VyY2VfdGltZSwgYWVzKHggPSB5ZWFyLCB5ID0gTiwgZ3JvdXAgPSBzb3VyY2UsIGNvbG9yID0gc291cmNlKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEpKw0KICAgIHRoZW1lX2J3KCkrDQogIG15LnRoZW1lKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0PTAuOTUsdmp1c3Q9MC4yLCBzaXplID0gOSkpKw0KICB5bGFiKCJOIHJldHJpZXZlZCBhcnRpY2xlcyIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZT0yKSkNCg0KcGxvdF9zb3VyY2VfdGltZQ0KDQoNCiNnZ3NhdmUoInBsb3RzX3JlcG8vcGxvdF9zb3VyY2VfdGltZS5wbmciLCBoZWlnaHQgPSA3LCB3aWR0aCA9IDEzKQ0KDQpgYGANCg0KDQoNCiMjIDEwLiBMb2NhdGlvbiBvZiBpbmZvcm1hdGlvbg0KDQpgYGB7cn0NCg0KZGZfbG9jYXRpb25faW5mbyA8LSBjb21wdXRlX2RmX2xvY2F0aW9uX2luZm8oZGYgPSBkYXRhc2V0KQ0KDQpgYGANCg0KDQpgYGB7cn0NCmRmX3Bsb3RfbG9jX3NwYXRpYWwucmFuZ2UgPC0gZGZfbG9jYXRpb25faW5mb1tkZl9sb2NhdGlvbl9pbmZvJHNwYXRpYWxfcmFuZ2VfcG9zaXRpb24gIT0gIiIsXQ0KDQpkZl9wbG90X2xvY190ZW1wb3JhbC5yYW5nZSA8LSBkZl9sb2NhdGlvbl9pbmZvW2RmX2xvY2F0aW9uX2luZm8kdGVtcG9yYWxfcmFuZ2VfcG9zaXRpb24gIT0gIiIsXQ0KDQpkZl9wbG90X2xvY190ZW1wb3JhbC5kdXJhdGlvbiA8LSBkZl9sb2NhdGlvbl9pbmZvW2RmX2xvY2F0aW9uX2luZm8kdGVtcG9yYWxfZHVyYXRpb25fcG9zaXRpb24gIT0gIiIsXQ0KDQoNCg0KcGxvdF9zcGF0X3JhbmdlX3Bvc2l0aW9uIDwtIGdncGxvdChuYS5vbWl0KGRmX3Bsb3RfbG9jX3NwYXRpYWwucmFuZ2UpLCBhZXMoeD1zcGF0aWFsX3JhbmdlX3Bvc2l0aW9uLCBmaWxsID0gZGF0YXNldF9sb2NhdGlvbikpICsgDQogIGdlb21fYmFyKGFlcyh5ID0gKC4uY291bnQuLikpKSArDQogIGdlb21fdGV4dChzdGF0PSdjb3VudCcsIGFlcyhsYWJlbD0uLmNvdW50Li4pLHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSsNCiAgZ2d0aXRsZSgiU3BhdGlhbCByYW5nZSBpbmZvcm1hdGlvbiIpKw0KICB0aGVtZV9idygpKw0KICBteS50aGVtZSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdD0wLjk1LHZqdXN0PTAuMiwgc2l6ZSA9IDkpKSsNCiAgeWxhYigiTiByZXRyaWV2ZWQgYXJ0aWNsZXMiKSArDQogIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2U9MikpDQoNCg0KcGxvdF90ZW1wX3JhbmdlX3Bvc2l0aW9uIDwtIGdncGxvdChuYS5vbWl0KGRmX3Bsb3RfbG9jX3RlbXBvcmFsLnJhbmdlKSwgYWVzKHg9dGVtcG9yYWxfcmFuZ2VfcG9zaXRpb24sIGZpbGwgPSBkYXRhc2V0X2xvY2F0aW9uKSkgKyANCiAgZ2VvbV9iYXIoYWVzKHkgPSAoLi5jb3VudC4uKSkpICsNCiAgZ2VvbV90ZXh0KHN0YXQ9J2NvdW50JywgYWVzKGxhYmVsPS4uY291bnQuLikscG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpKw0KICAgIGdndGl0bGUoIlRlbXBvcmFsIHJhbmdlIGluZm9ybWF0aW9uIikrDQogIHRoZW1lX2J3KCkrDQogIG15LnRoZW1lKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0PTAuOTUsdmp1c3Q9MC4yLCBzaXplID0gOSkpKw0KICB5bGFiKCJOIHJldHJpZXZlZCBhcnRpY2xlcyIpICsNCiAgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMobi5kb2RnZT0yKSkNCg0KDQpkZl9wbG90X2xvY190ZW1wb3JhbC5kdXJhdGlvbiA8LSBnZ3Bsb3QobmEub21pdChkZl9wbG90X2xvY190ZW1wb3JhbC5kdXJhdGlvbiksIGFlcyh4PXRlbXBvcmFsX2R1cmF0aW9uX3Bvc2l0aW9uLCBmaWxsID0gZGF0YXNldF9sb2NhdGlvbikpICsgDQogIGdlb21fYmFyKGFlcyh5ID0gKC4uY291bnQuLikpKSArDQogIGdlb21fdGV4dChzdGF0PSdjb3VudCcsIGFlcyhsYWJlbD0uLmNvdW50Li4pLHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSsNCiAgZ2d0aXRsZSgiVGVtcG9yYWwgZHVyYXRpb24gaW5mb3JtYXRpb24iKSsNCiAgdGhlbWVfYncoKSsNCiAgbXkudGhlbWUrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3Q9MC45NSx2anVzdD0wLjIsIHNpemUgPSA5KSkrDQogIHlsYWIoIk4gcmV0cmlldmVkIGFydGljbGVzIikgKw0KICBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhuLmRvZGdlPTIpKQ0KDQoNCnBsb3RfbG9jYXRpb25fc3BhdGlvdGVtcG9yYWxfaW5mb3JtYXRpb24gPC0gZ2dhcnJhbmdlKHBsb3Rfc3BhdF9yYW5nZV9wb3NpdGlvbiwNCiAgICAgICAgICBwbG90X3RlbXBfcmFuZ2VfcG9zaXRpb24sDQogICAgICAgICAgZGZfcGxvdF9sb2NfdGVtcG9yYWwuZHVyYXRpb24sDQogICAgICAgICAgbmNvbCA9IDEsDQogICAgICAgICAgbnJvdyA9IDMsIA0KICAgICAgICAgIGNvbW1vbi5sZWdlbmQgPSBUUlVFLA0KICAgICAgICAgIGxlZ2VuZCA9ICJ0b3AiKQ0KDQoNCnBsb3RfbG9jYXRpb25fc3BhdGlvdGVtcG9yYWxfaW5mb3JtYXRpb24NCg0KDQojZ2dzYXZlKCJwbG90c19yZXBvL3Bsb3RfbG9jYXRpb25fc3BhdGlvdGVtcG9yYWxfaW5mb3JtYXRpb24ucG5nIiwgaGVpZ2h0ID0gMTYsIHdpZHRoID0gNykNCg0KYGBgDQoNCg0KDQoNCiMgbG9jYXRpb24gLSBkYXRhc2V0IHR5cGUNCg0KDQpXZSBldmFsdWF0ZSB0aGUgZmVhc2liaWxpdHkgdG8gYXV0b21hdGljYWxseSByZXRyaWV2ZSB0aGUgaW5mb3JtYXRpb24gb24gdGhlIGRhdGFzZXQgdHlwZSBieSBsb29raW5nIGF0IHdoZXRoZXIgYXV0aG9ycyBtYWtlIGV4cGxpY2l0IHRoZSB0eXBlIG9mIGRhdGFzZXQgaW4gZWl0aGVyIHRoZSB0aXRsZSBvciBhYnN0cmFjdC4NCg0KVHlwZSBvZiBkYXRhc2V0IHNob3VsZCBmYWxsIGluIG9uZSBvZiB0aGUgZm9sbG93aW5nIGNhdGVnb3JpZXMgb3Igc3lub255bXM6DQoNCmBgYHtyfQ0KZGZfZGF0YXNldF90eXBlcyA8LSByZWFkLmNzdigiLi4vZGF0YS9kYXRhc2V0X3R5cGVzLmNzdiIsIHNlcCA9ICI7IikNCmRmX2RhdGFzZXRfdHlwZXMNCmBgYA0KDQpJIHdpbGwgYWRkIHRoZSBmb2xsb3dpbmcgc3lub255bXM6DQoNCnByZXNlbmNlLWFic2VuY2U6IGRldGVjdGlvbiwgY2FwdHVyZQ0KDQpFQlYgZ2VuZXRpYyBhbmFseXNlczogMTZTLCAxOFMsIGdlbmV0aWMgZGF0YSwgbWljcm9zYXRlbGl0ZXMsIGJhcmNvZGVzKD8pLCBoYXBsb3R5cGVzLCBlRE5BLCBTTlBzDQoNCg0KYGBge3J9DQpkZl9kYXRhc2V0X3R5cGVzW25yb3coZGZfZGF0YXNldF90eXBlcykrMSxdIDwtIGMoInByZXNlbmNlLWFic2VuY2UiLCAiZGV0ZWN0aW9uIiwgInN5bm9ueW0iKQ0KZGZfZGF0YXNldF90eXBlc1tucm93KGRmX2RhdGFzZXRfdHlwZXMpKzEsXSA8LSBjKCJwcmVzZW5jZS1hYnNlbmNlIiwgImNhcHR1cmUiLCAic3lub255bSIpDQoNCmRmX2RhdGFzZXRfdHlwZXNbbnJvdyhkZl9kYXRhc2V0X3R5cGVzKSsxLF0gPC0gYygiRUJWIGdlbmV0aWMgYW5hbHlzZXMiLCAiMTZTIiwgIm1ldGhvZHMiKQ0KZGZfZGF0YXNldF90eXBlc1tucm93KGRmX2RhdGFzZXRfdHlwZXMpKzEsXSA8LSBjKCJFQlYgZ2VuZXRpYyBhbmFseXNlcyIsICIxOFMiLCAibWV0aG9kcyIpDQpkZl9kYXRhc2V0X3R5cGVzW25yb3coZGZfZGF0YXNldF90eXBlcykrMSxdIDwtIGMoIkVCViBnZW5ldGljIGFuYWx5c2VzIiwgImJhcmNvZGVzIiwgIm1ldGhvZHMiKQ0KZGZfZGF0YXNldF90eXBlc1tucm93KGRmX2RhdGFzZXRfdHlwZXMpKzEsXSA8LSBjKCJFQlYgZ2VuZXRpYyBhbmFseXNlcyIsICJoYXBsb3R5cGVzIiwgIm1ldGhvZHMiKQ0KZGZfZGF0YXNldF90eXBlc1tucm93KGRmX2RhdGFzZXRfdHlwZXMpKzEsXSA8LSBjKCJFQlYgZ2VuZXRpYyBhbmFseXNlcyIsICJlRE5BIiwgIm1ldGhvZHMiKQ0KZGZfZGF0YXNldF90eXBlc1tucm93KGRmX2RhdGFzZXRfdHlwZXMpKzEsXSA8LSBjKCJFQlYgZ2VuZXRpYyBhbmFseXNlcyIsICJTTlBzIiwgIm1ldGhvZHMiKQ0KDQpkZl9kYXRhc2V0X3R5cGVzDQpgYGANCg0KDQoNCkRldGVjdGluZyB0aGUgd29yZHMgaW4gdGl0bGUgb3IgYWJzdHJhY3QNCg0KDQoNCmBgYHtyfQ0KDQoNCmRhdGFzZXQxIDwtIGRhdGFzZXRbLXdoaWNoKGlzLm5hKGRhdGFzZXRbLCJkZXNjcmlwdGlvbiJdKSksXQ0KZGF0YXNldDIgPC0gZGF0YXNldDFbLXdoaWNoKGRhdGFzZXQxJHRpdGxlID09ICIiKSxdDQoNCnVybCA8LSBjKCkNCmRhdGFzZXRfdHlwZSA8LSBjKCkNCmtleXdvcmRfYWJzIDwtIGxpc3QoKQ0Ka2V5d29yZF90aXRsZSA8LSBsaXN0KCkNCiNrZXl3b3JkX3R5cGUgPC0gYygpDQppbl90aXRsZSA8LSBjKCkNCmluX2Fic3RyYWN0IDwtIGMoKQ0KDQoNCg0KZm9yIChpIGluIDE6bnJvdyhkYXRhc2V0MikpIHsNCiAgDQogIA0KICANCiAgZGF0YXNldF90eXBlW2ldIDwtIGRhdGFzZXQyW2ksICJkYXRhX3R5cGUiXQ0KICB1cmxbaV0gPC0gZGF0YXNldDJbaSwgInVybCJdDQogIA0KICANCiAgDQogIA0KICAjIHNlYXJjaCBvbiB0aGUgYWJzdHJhY3QgYW5kIG5vdGUgdGhlIGxpc3Qgb2Yga2V5d29yZHMgdGhhdCBtYXRjaCB0aGUgZGF0YXNldCB0eXBlcw0KDQogIGtleXdvcmRfYWJzW1tpXV0gPC0gdW5pcXVlKGdldF9rZXl3b3JkcyhpbnB1dF9zdHJpbmcgPSBkYXRhc2V0MiRkZXNjcmlwdGlvbltpXSwgDQogICAgICAgICAgICAgICBkYXRhc2V0X3R5cGVzID0gIGRmX2RhdGFzZXRfdHlwZXMpKQ0KICANCiAgIyBpZiB0aGUgbGlzdCBvZiBrZXl3b3JkcyBoYXMgMSBvciBtb3JlIGVudHJ5LCB0aGVuIG5vdGUgdGhhdCB3ZSBmb3VuZCBpbmZvcm1hdGlvbiBpbiB0aGUgYWJzdHJhY3QNCiAgDQogIGlmKGxlbmd0aChrZXl3b3JkX2Fic1tpXVshc2FwcGx5KGtleXdvcmRfYWJzW2ldLCBpcy5udWxsKV0pID09IDApew0KICAgIA0KICAgIGluX2Fic3RyYWN0W2ldIDwtICJubyINCiAgICANCiAgfSBlbHNlIGlmIChsZW5ndGgoa2V5d29yZF9hYnNbaV1bIXNhcHBseShrZXl3b3JkX2Fic1tpXSwgaXMubnVsbCldKSA+IDApew0KICAgIA0KICAgIGluX2Fic3RyYWN0W2ldIDwtICJ5ZXMiDQogICAgDQogIH0NCiAgDQogIA0KICANCg0KICAjIHNlYXJjaCBvbiB0aGUgdGl0bGUgYW5kIG5vdGUgdGhlIGxpc3Qgb2Yga2V5d29yZHMgdGhhdCBtYXRjaCB0aGUgZGF0YXNldCB0eXBlcw0KDQogIGtleXdvcmRfdGl0bGVbW2ldXSA8LSB1bmlxdWUoZ2V0X2tleXdvcmRzKGlucHV0X3N0cmluZyA9IGRhdGFzZXQyJHRpdGxlW2ldLCANCiAgICAgICAgICAgICAgIGRhdGFzZXRfdHlwZXMgPSAgZGZfZGF0YXNldF90eXBlcykpDQogIA0KICAjIGlmIHRoZSBsaXN0IG9mIGtleXdvcmRzIGhhcyAxIG9yIG1vcmUgZW50cnksIHRoZW4gbm90ZSB0aGF0IHdlIGZvdW5kIGluZm9ybWF0aW9uIGluIHRoZSBhYnN0cmFjdA0KICANCiAgaWYobGVuZ3RoKGtleXdvcmRfdGl0bGVbaV1bIXNhcHBseShrZXl3b3JkX3RpdGxlW2ldLCBpcy5udWxsKV0pID09IDApew0KICAgIA0KICAgIGluX3RpdGxlW2ldIDwtICJubyINCiAgICANCiAgfSBlbHNlIGlmIChsZW5ndGgoa2V5d29yZF90aXRsZVtpXVshc2FwcGx5KGtleXdvcmRfdGl0bGVbaV0sIGlzLm51bGwpXSkgPiAwKXsNCiAgICANCiAgICBpbl90aXRsZVtpXSA8LSAieWVzIg0KICAgIA0KICB9IA0KICANCiAgDQogIA0KfQ0KDQoNCg0KDQojZGF0YS5mcmFtZShkYXRhc2V0X3R5cGUsIGtleXdvcmRfYWJzLCBrZXl3b3JkX3RpdGxlLCBpbl90aXRsZSwgaW5fYWJzdHJhY3QpDQoNCg0KZGZfZGF0YV90eXBlX2FicyA8LSBkYXRhLmZyYW1lKHVybCwgZGF0YXNldF90eXBlLCBpbl9hYnN0cmFjdCwgaW5fdGl0bGUpDQpkZl9kYXRhX3R5cGVfYWJzJGtleXdvcmRfYWJzIDwtIGtleXdvcmRfYWJzDQoNCiNlbGltaW5hdGUgdGhvc2UgZGF0YXNldHMgd2l0aG91dCBkYXRhX3R5cGUgaW5mbw0KDQpkZl9kYXRhX3R5cGVfYWJzMSA8LSBkZl9kYXRhX3R5cGVfYWJzW2RmX2RhdGFfdHlwZV9hYnMkZGF0YXNldF90eXBlICE9ICIiLF0NCg0KZGZfZGF0YV90eXBlX2FiczENCg0KDQpgYGANCg0KDQoNCkZvciBzb21lIHJlYXNvbiwga2V5d29yZF90aXRsZSBoYXMgMyBsZXNzIGVudHJpZXMgdGhhdCBrZXl3b3JkX2Fic3RyYWN0LCBhbmQgSSBjYW4ndCBmaWd1cmUgb3V0IHdoeS4gU28gZm9yIG5vdyBJIGNhbnQgb2J0YWluIHRoZSBsaXN0IG9mIHdvcmRzIHRoYXQgYXBwZWFyIGluIHRoZSB0aXRsZS4NCg0KDQpgYGB7cn0NCg0KcHJpbnQocGFzdGUobGVuZ3RoKHdoaWNoKGRmX2RhdGFfdHlwZV9hYnMxJGluX2Fic3RyYWN0ID09ICJ5ZXMiKSksIA0KICAgICAgICAgICAgIndpdGggZGF0YXNldCB0eXBlIG9yIHN5bm9ueW0gZXhwbGljaXQgaW4gdGhlIGFic3RyYWN0LCBvdXQgb2YiLCBsZW5ndGgoZGZfZGF0YV90eXBlX2FiczEkaW5fYWJzdHJhY3QpKSkNCg0KcHJpbnQocGFzdGUoInNvIiwgDQogICAgICByb3VuZChsZW5ndGgod2hpY2goZGZfZGF0YV90eXBlX2FiczEkaW5fYWJzdHJhY3QgPT0gInllcyIpKS9sZW5ndGgoZGZfZGF0YV90eXBlX2FiczEkaW5fYWJzdHJhY3QpKjEwMCwgMSksDQoiJSIpKQ0KDQoNCg0KYGBgDQoNCmBgYHtyfQ0KcHJpbnQocGFzdGUobGVuZ3RoKHdoaWNoKGRmX2RhdGFfdHlwZV9hYnMxJGluX3RpdGxlID09ICJ5ZXMiKSksIA0KICAgICAgICAgICAgIndpdGggZGF0YXNldCB0eXBlIG9yIHN5bm9ueW0gZXhwbGljaXQgaW4gdGhlIHRpdGxlLCBvdXQgb2YiLCBsZW5ndGgoZGZfZGF0YV90eXBlX2FiczEkaW5fdGl0bGUpKSkNCg0KcHJpbnQocGFzdGUoInNvIiwgDQogICAgICByb3VuZChsZW5ndGgod2hpY2goZGZfZGF0YV90eXBlX2FiczEkaW5fdGl0bGUgPT0gInllcyIpKS9sZW5ndGgoZGZfZGF0YV90eXBlX2FiczEkaW5fdGl0bGUpKjEwMCwgMSksDQoiJSIpKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0K